package com.usefullc.system.service;

import com.google.common.reflect.ClassPath;
import com.usefullc.common.enums.*;
import com.usefullc.common.exception.BizException;
import com.usefullc.system.vo.DataOptionVo;
import com.usefullc.system.vo.OptionVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author: Sampson
 * @date: 2022-06-21 22:07
 */
@Slf4j
@Service
public class CommonService extends AbstractService {

    private List<DataOptionVo> dataList = new ArrayList<>();

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private JobTemplateService jobTemplateService;

//    @PostConstruct
    public void init(){
        try{
            log.info("init enums data");
//            String packageName = "com.usefullc.*.enums";
//            logger.info("classLoader={}",this.getClass().getClassLoader());
//            Set<? extends Class<?>> enumClsList = ClassPath.from(ClassLoader.getSystemClassLoader())
//                    .getAllClasses().stream().filter(clazz -> clazz.getPackageName().matches(packageName))
//                    .map(clazz -> clazz.load())
//                    .collect(Collectors.toSet());


            ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
            MetadataReaderFactory metaReader = new CachingMetadataReaderFactory(resourceLoader);
            Resource[] resources = resolver.getResources("classpath*:com/usefullc/**/enums/*.class");

            List<Class> enumClsList = new ArrayList<>();
            for (Resource resource : resources) {
                MetadataReader reader = metaReader.getMetadataReader(resource);
                String className = reader.getClassMetadata().getClassName();
                enumClsList.add(Class.forName(className));
            }

            log.info("enumClsList empty={}", CollectionUtils.isEmpty(enumClsList));
            for (Class<?> enumCls : enumClsList) {

//                Enum e = enumCls;
                Object [] values = (Object[]) enumCls.getMethod("values").invoke(enumCls);
                log.info("enumCls={}",enumCls);
                dataList.add(wrapDataOptionVo(enumCls,values,"code","value"));
            }


        }catch (Exception e){
            throw new BizException(e);
        }
    }
    public List<DataOptionVo> getEnumDataOptions(){


//        List<DataOptionVo> dataList = new ArrayList<>();
//        dataList.add(wrapDataOptionVo(LocalEnum.class,FormDataFromEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(SmsCodeTypeEnum.class,FormDataFromEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(LoginTypeEnum.class,FormDataFromEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(FormDataFromEnum.class,FormDataFromEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(ValidTypeEnum.class,ValidTypeEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(UserStatusEnum.class,UserStatusEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(UserGenderEnum.class,UserStatusEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(UserTypeEnum.class,UserStatusEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(AppTypeEnum.class,AppTypeEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(FormTypeEnum.class,FormTypeEnum.values(),"code","value"));
//        dataList.add(wrapDataOptionVo(ApiParameterInOrOutEnum.class,ApiParameterInOrOutEnum.values(),"code","value"));


        return dataList;
    }

    public DataOptionVo getByEnumName(String enumCode){
        List<DataOptionVo> enumDataOptions = getEnumDataOptions();
        for (DataOptionVo enumDataOption : enumDataOptions) {
            if(StringUtils.equalsIgnoreCase(enumDataOption.getName(),enumCode)){
                return enumDataOption;
            }
        }
        return null;

    }


    private  DataOptionVo wrapDataOptionVo(Class cls,Object [] values ,String valueFieldName,String textFieldName){
        try{
            DataOptionVo dataOptionVo = new DataOptionVo();
            dataOptionVo.setName(getEnumKey(cls));
            List<OptionVo> optionList = new ArrayList<>();
            dataOptionVo.setOptionList(optionList);
            for (Object obj : values) {
                Object value = FieldUtils.getField(obj.getClass(),valueFieldName,true).get(obj);
                String text = FieldUtils.getField(obj.getClass(),textFieldName,true).get(obj).toString();
                OptionVo optionVo = new OptionVo();
                optionVo.setText(text);
                optionVo.setLabel(text);
                optionVo.setTitle(text);
                optionVo.setValue(value);
                optionList.add(optionVo);
            }
            return dataOptionVo;

        }catch (Exception e){
            throw new BizException(e);
        }
    }

    private String getEnumKey(Class cls) {
        String code = cls.getSimpleName();
        return StringUtils.uncapitalize(code);
    }


}
